import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;

import java.util.Random;

public class EnemyAI {
    PulpFireScene parent;
    SimulatedInput enemyInput;

    Vec2 currentPosition;
    Vec2 targetPosition;

    Vec2 currentMousePosition;
    Vec2 targetMousePosition;
    Body targetBody;

    int difficultyLevel;
    final int minDifficultyLevel = 0;
    final int maxDifficultyLevel = 5;

    enum TargetStrategy {NEAREST, FARTHEST, BIGGEST_CLUSTER,
                         RANDOM, MOVING_TOWARDS, MOVING_AWAY};
    enum MovementStrategy {WANDER, MIDDLE_LEFT, FOLLOW_TARGET};
    enum ShootStrategy {ALWAYS_SHOOT, FULL_CHARGE, SHOOT_ON_LOCK,
                        RANDOM_WAIT};

    TargetStrategy targetStrategy;
    MovementStrategy movementStrategy;
    ShootStrategy shootStrategy;

    boolean targetLocked;

    static final float maxMouseMovePerFrame = 0.3f;

    public EnemyAI(PulpFireScene _parent) {
        parent = _parent;
        enemyInput = parent.enemyInput;
        difficultyLevel = 0;
        targetStrategy = TargetStrategy.RANDOM;
        movementStrategy = MovementStrategy.WANDER;
        shootStrategy = ShootStrategy.RANDOM_WAIT;
        targetLocked = false;
        targetPosition = new Vec2();
        currentPosition = new Vec2();
        currentMousePosition = new Vec2();
        targetMousePosition = new Vec2();
    }

    public int getDifficultyLevel() {
        return difficultyLevel;
    }

    public void setDifficultyLevel(int level) {
        difficultyLevel = level;
        if (level < minDifficultyLevel) difficultyLevel = minDifficultyLevel;
        if (level > maxDifficultyLevel) difficultyLevel = maxDifficultyLevel;
    }

    public void updateEnemyInput() {
        currentPosition = parent.jetPackR.getWorldCenter();
        calcShootingTarget();
        calcMovementTarget();
        moveMouse();
        pressKeys();
        doClicks();
    }

    private void calcShootingTarget() {
        if (targetLocked && targetBody != null) {
            targetMousePosition.set(targetBody.getWorldCenter());
            return;
        }
        switch(targetStrategy) {
            case NEAREST:
                break;
            case FARTHEST:
                break;
            case RANDOM:
                int nBodies = parent.puckBits.size();
                if (nBodies == 0) return;
                int n = (int) (Math.random()*nBodies);
                targetBody = parent.puckBits.get(n);
                targetMousePosition = targetBody.getWorldCenter().clone();
                targetLocked = true;
                break;
            case BIGGEST_CLUSTER:
                break;
            case MOVING_TOWARDS:
                break;
            case MOVING_AWAY:
                break;
        }
    }

    private void calcMovementTarget() {
        switch(movementStrategy) {
            case FOLLOW_TARGET:
                break;
            case MIDDLE_LEFT:
                break;
            case WANDER:
                final float wanderSpeed = 0.1f;
                Vec2 currentDir = targetPosition.sub(currentPosition);
                currentDir.normalize();
                currentDir.addLocal(new Vec2(-0.1f+wanderSpeed*(float)(Math.random()-0.5),
                                             wanderSpeed*(float)(Math.random()-0.5)));
                targetPosition = currentPosition.add(currentDir);
                break;
        }
    }

    private void moveMouse() {
        Vec2 diff = targetMousePosition.sub(currentMousePosition);
        float diffLength = diff.normalize();
        if (diffLength > maxMouseMovePerFrame) diff.mulLocal(maxMouseMovePerFrame);
        else diff.mulLocal(diffLength);
        currentMousePosition.addLocal(diff);
        enemyInput.setMousePosition(currentMousePosition);
    }

    private void pressKeys() {
        final float threshold = 0.1f;
        boolean u,d,l,r;
        u = d = l = r = false;
        if (targetPosition.x - currentPosition.x > threshold) {
            r = true;
        } else if (targetPosition.x - currentPosition.x < -threshold) {
            l = true;
        }
        if (targetPosition.y - currentPosition.y > threshold) {
            u = true;
        } else if (targetPosition.y - currentPosition.y < -threshold) {
            d = true;
        }
        enemyInput.setArrows(u,d,l,r);
    }

    int timeSinceShot = 0;
    int timeToFullCharge = 45;
    int reloadDelay = 10;

    int shotTimeTarget;
    boolean shotTimeTargetSet = false;
    
    private void doClicks() {
        ++timeSinceShot;
        // All decent strategies involve charging up immediately
        if (enemyInput.getMouseDown() == false) {
            enemyInput.mouseDown();
            return;
        }
        switch(shootStrategy) {
            case ALWAYS_SHOOT:
                break;
            case FULL_CHARGE:
                break;
            case RANDOM_WAIT:
                if (shotTimeTargetSet) {
                    if (timeSinceShot >= shotTimeTarget) {
                        enemyInput.mouseUp();
                        timeSinceShot = 0;
                        shotTimeTargetSet = false;
                        targetLocked = false;
                    }
                    //keep waiting...
                } else {
                    float random = (float)Math.random();
                    random *= (2*timeToFullCharge - reloadDelay);
                    random += reloadDelay;
                    shotTimeTarget = (int)random;
                    shotTimeTargetSet = true;
                    if (targetBody != null) targetLocked = true;
                }
                break;
            case SHOOT_ON_LOCK:
                break;
        }
    }


}
